﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Threading;
using DiagnosticCenter.ViewModel;
using DiagnosticCenter.Web;

namespace DiagnosticCenter.View
{
    public partial class viewTestingTest
    {
        public TestInfo CurrentTest;
        public TestLog CurrentTestLog;
        public DispatcherTimer TestTimer = new DispatcherTimer();
        private TimeSpan sessionPass;
        public int CurrentQuestion;

        public DatabaseContext ctx = new DatabaseContext();
        public int TestIDX = 5; //разобраться с этим числом
        
        public viewTestingTest()
        {
            InitializeComponent();

        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            //Инициализация теста
            CurrentTest = new TestInfo();
            CurrentQuestion = 0;
            ctx.Load(ctx.GetTblTestTotalQuery(), LoadTestCompleted, null);

            TestStats.DataContext = CurrentTestLog;
        }

        private void LoadTestCompleted(LoadOperation<tblTest> lo)
        {
            //Загрузка теста
            LoadTest(TestIDX);
            
            //Инициализация первого вопроса
            InitQuestion();

            //Инициализация отчета по тесту
            CurrentTestLog = new TestLog();
            CurrentTestLog.UserID = WebContext.Current.User.UserID;
            CurrentTestLog.TestID = CurrentTest.TestID;
            CurrentTestLog.DateStart = DateTime.Now;
            CurrentTestLog.UserFullName = String.Format("{0} {1}", WebContext.Current.User.LastName, WebContext.Current.User.FirstName);
            CurrentTestLog.GroupName = WebContext.Current.User.tblGroup.Name;
            CurrentTestLog.SubjectName = CurrentTest.SubjectName;
            CurrentTestLog.TestName = CurrentTest.TestName;
            CurrentTestLog.TotalTime = CurrentTest.TimeTotal;
            CurrentTestLog.QuestionCount = CurrentTest.QuestionCount;
            CurrentTestLog.State = TestLog.TestingState.TS_PROGRESS;

            //Ограничение теста по времени
            if (CurrentTest.TimeTotal > 0)
            {
                labelSessionStart.Text = CurrentTestLog.DateStart.ToString("HH:mm:ss");
                TestTimer.Tick += TestingTimer_Tick;
                TestTimer.Interval = new TimeSpan(0, 0, 1);
                TestTimer.Start();
            }
        }

        //Загрузка теста
        public void LoadTest(int testid)
        {
            var test = ctx.tblTests.Where(e => e.TestID == testid).FirstOrDefault();

            CurrentTest.TestID = test.TestID;
            CurrentTest.SubjectID = test.SubjectID;
            CurrentTest.TestName = test.TestName;
            if (test.TotalTime != null) CurrentTest.TimeTotal = (int)test.TotalTime;
            if (test.TestMode != null) CurrentTest.TestMode = (int)test.TestMode;
            if (test.TestRating != null) CurrentTest.TestRating = (int)test.TestRating;
            if (test.QuestionCount != null) CurrentTest.QuestionCount = (int)test.QuestionCount;
            if (test.QuestionResult != null) CurrentTest.QuestionResult = (int)test.QuestionResult;
            CurrentTest.ShowTestRules = test.TestRules;
            CurrentTest.AllowRefuse = test.AllowRefuse;
            CurrentTest.AllowTips = test.AllowTips;
            CurrentTest.ResultPrint = test.ResultPrint;
            CurrentTest.ResultSave = test.ResultSave;
            CurrentTest.ResultShow = test.ResultShow;
            CurrentTest.ShuffleQuestions = test.ShuffleQuestions;
            CurrentTest.ShuffleAnswers = test.ShuffleAnswers;
            
            //TODO: Срочно: Выборка вопросов с учетом смешивания, уровня сложности
            foreach (var question in test.tblQuestions)
            {
                var questionInfo = new QuestionInfo();
                questionInfo.QuestionID = question.QuestionID;
                questionInfo.QuestionText = question.Text;
                if (question.AnswerType != null) questionInfo.AnswerType = (AnswerType)question.AnswerType;
                if (question.Difficulty != null) questionInfo.QuestionDifficulty = (int)question.Difficulty;
                questionInfo.AnswerLite = question.AnswerLite;
                if (question.AnswerImage != null) questionInfo.AnswerImage = (bool)question.AnswerImage;

                //обработка бинарных вопросов
                if (questionInfo.AnswerType == AnswerType.AT_Binary)
                {
                    var answerInfo = new AnswerInfo();
                    answerInfo.AnswerText = "Да";
                    answerInfo.AnswerTrue = questionInfo.AnswerLite == "1";
                    questionInfo.Answers.Add(answerInfo);

                    answerInfo = new AnswerInfo();
                    answerInfo.AnswerText = "Нет";
                    answerInfo.AnswerTrue = questionInfo.AnswerLite == "0";
                    questionInfo.Answers.Add(answerInfo);
                } else

                //обработка остальных вопросов
                foreach (var answer in question.tblAnswers)
                {
                    var answerInfo = new AnswerInfo();
                    answerInfo.AnswerID = answer.AnswerID;
                    answerInfo.AnswerText = answer.Text;
                    answerInfo.RowNumber = Convert.ToInt32(answer.RowNum);
                    answerInfo.AnswerNumber = Convert.ToInt32(answer.AnswerNum);
                    if (answer.IsTrue != null) answerInfo.AnswerTrue = (bool)answer.IsTrue;
                    if (questionInfo.AnswerImage) answerInfo.Image = String.Format("/images/questions/a{0}.png", answerInfo.AnswerID);

                    questionInfo.Answers.Add(answerInfo);
                }

                //Случайный порядок ответов
                if (CurrentTest.ShuffleAnswers)
                {
                    var rnd = new Random();
                    questionInfo.Answers = ToObservableCollection(questionInfo.Answers.OrderBy(x => rnd.Next()));
                }

                CurrentTest.Questions.Add(questionInfo);
            }

            //Случайный порядок вопросов
            if (CurrentTest.ShuffleQuestions)
            {
                var rnd = new Random();
                CurrentTest.Questions = ToObservableCollection(CurrentTest.Questions.OrderBy(x => rnd.Next()));
            }
        }
        
        private void TestingTimer_Tick(object sender, EventArgs e)
        {
            sessionPass = DateTime.Now - CurrentTestLog.DateStart;
            DateTime sessionRemaining = DateTime.MinValue.AddMinutes(CurrentTest.TimeTotal) - sessionPass;
            labelSessionPass.Text = String.Format("{0} мин {1:D2} сек", sessionPass.Minutes, sessionPass.Seconds);
            labelSessionRemaining.Text = String.Format("{0} мин {1:D2} сек", sessionRemaining.Minute, sessionRemaining.Second);

            if ((sessionRemaining.Minute == 0) && (sessionRemaining.Second == 0))
            {
                FinishTest();
            }
        }

        private void FinishTest()
        {
            TestTimer.Stop();
            CurrentTestLog.State = TestLog.TestingState.TS_FINISHED;

            //Расчет рейтинга и количества правильных ответов (переделать)
            CurrentTestLog.TestRating = 10;
            CurrentTestLog.RightAnswers = 20;

            //Запись результата
            var result = new tblResult();
            result.UserID = WebContext.Current.User.UserID;
            result.TestID = CurrentTest.TestID;
            result.RightAnswers = CurrentTestLog.RightAnswers;
            result.Rating = CurrentTestLog.TestRating;
            result.DateStart = CurrentTestLog.DateStart;
            result.DateFinish = CurrentTestLog.DateStart + sessionPass;
            
            //Запись элементов результата
            foreach (var item in CurrentTestLog.Questions)
            {
                var ResultItem = new tblResultItem();
                ResultItem.QuestionID = item.QuestionID;
                ResultItem.IsRight = item.IsRight;
                ResultItem.ResultText = item.AnswerText;

                ctx.tblResultItems.Add(ResultItem);
                result.tblResultItems.Add(ResultItem);
            }
            ctx.tblResults.Add(result);

            ctx.SubmitChanges();
        }

        #region Инициализация вопросов
        private void InitQuestion()
        {
            // Инициализация вопроса
            QuestionHeader.Text = String.Format("Вопрос: {0} из {1}", CurrentQuestion + 1, CurrentTest.QuestionCount);
            richQuestion.Blocks.Clear();
            var para = new Paragraph { FontSize = 18, FontFamily = new FontFamily("Times New Roman") };
            para.Inlines.Add(new Run { Text = CurrentTest.Questions[CurrentQuestion].QuestionText } );
            richQuestion.Blocks.Add(para);

            //Инициализация ответа
            switch (CurrentTest.Questions[CurrentQuestion].AnswerType)
            {
                case AnswerType.AT_Binary:
                case AnswerType.AT_SelectOne:
                    InitAnswerSelectOne();
                    break;
                case AnswerType.AT_SelectMulti:
                    InitAnswerSelectMulti();
                    break;
                case AnswerType.AT_Arrange:
                    InitAnswerArrange();
                    break;
                case AnswerType.AT_Relation:
                    InitAnswerRelation();
                    break;
                case AnswerType.AT_SimpleText:
                    InitAnswerSimpleText();
                    break;
            }
        }

        private void InitAnswerSelectOne()
        {
            panelAnswer.Children.Clear();
            var AnswerSelect = new uiAnswerSelect();
            AnswerSelect.Name = "AnswerSelect";
            AnswerSelect.SetAnswerType(1, CurrentTest.Questions[CurrentQuestion].AnswerImage);
            AnswerSelect.listAnswer.ItemsSource = CurrentTest.Questions[CurrentQuestion].Answers;
            panelAnswer.Children.Add(AnswerSelect);
        }
        
        private void InitAnswerSelectMulti()
        {
            panelAnswer.Children.Clear();
            var AnswerSelect = new uiAnswerSelect();
            AnswerSelect.Name = "AnswerSelect";
            AnswerSelect.SetAnswerType(2, CurrentTest.Questions[CurrentQuestion].AnswerImage);
            AnswerSelect.listAnswer.ItemsSource = CurrentTest.Questions[CurrentQuestion].Answers;
            panelAnswer.Children.Add(AnswerSelect);
        }

        private void InitAnswerArrange()
        {
            panelAnswer.Children.Clear();
            var AnswerArrange = new uiAnswerArrange();
            AnswerArrange.Name = "AnswerArrange";
            AnswerArrange.ItemsList = ToObservableCollection(CurrentTest.Questions[CurrentQuestion].Answers);
            AnswerArrange.listArrange.ItemsSource = AnswerArrange.ItemsList;
            AnswerArrange.listArrange.DisplayMemberPath = "AnswerText";
            AnswerArrange.listArrange.SelectedIndex = 0;
            panelAnswer.Children.Add(AnswerArrange);
        }

        private void InitAnswerRelation()
        {
            panelAnswer.Children.Clear();
            var AnswerRelation = new uiAnswerRelation();
            AnswerRelation.Name = "AnswerRelation";
            AnswerRelation.listRelationLeft.ItemsSource = CurrentTest.Questions[CurrentQuestion].Answers.Where(e => e.RowNumber == 1);
            AnswerRelation.listRelationLeft.DisplayMemberPath = "AnswerText";
            AnswerRelation.ItemsList = ToObservableCollection(CurrentTest.Questions[CurrentQuestion].Answers.Where(e => e.RowNumber == 2));
            AnswerRelation.listRelationRight.ItemsSource = AnswerRelation.ItemsList;
            AnswerRelation.listRelationRight.DisplayMemberPath = "AnswerText";
            AnswerRelation.listRelationRight.SelectedIndex = 0;
            panelAnswer.Children.Add(AnswerRelation);
        }

        private void InitAnswerSimpleText()
        {
            panelAnswer.Children.Clear();
            var AnswerSimpleText = new uiAnswerText();
            AnswerSimpleText.Name = "AnswerSimpleText";
            panelAnswer.Children.Add(AnswerSimpleText);
        }

        #endregion

        #region Проверка правильность вопросов
        private void CheckAnswer()
        {
            bool IsRight = false;

            //TODO: Вывод сообщения, если не выбран ответ

            switch (CurrentTest.Questions[CurrentQuestion].AnswerType)
            {
                case AnswerType.AT_Binary:
                case AnswerType.AT_SelectOne:
                    IsRight = CheckQuestOne();
                    break;
                case AnswerType.AT_SelectMulti:
                    IsRight = CheckQuestMulti();
                    break;
                case AnswerType.AT_Arrange:
                    IsRight = CheckQuestArrange();
                    break;
                case AnswerType.AT_Relation:
                    IsRight = CheckQuestRelation();
                    break;
                case AnswerType.AT_SimpleText:
                    IsRight = CheckQuestSimpleText();
                    break;
            }

            //Вывод результата ответа
            if (CurrentTest.QuestionResult == 1)
                MessageBox.Show(IsRight ? "Ответ правилен" : "Ответ неправилен");
        }

        private bool CheckQuestOne()
        {
            var component = (uiAnswerSelect)panelAnswer.FindName("AnswerSelect");
            bool IsRight = false;

            foreach (AnswerInfo item in component.listAnswer.Items)
            {
                if (item.IsSelected)
                {
                    IsRight = item.AnswerTrue;
                    var testLogQuestions = new TestLogQuestions();
                    testLogQuestions.QuestionID = CurrentTest.Questions[CurrentQuestion].QuestionID;
                    testLogQuestions.QuestionText = CurrentTest.Questions[CurrentQuestion].QuestionText;
                    testLogQuestions.AnswerText = item.AnswerID.ToString();
                    testLogQuestions.IsRight = IsRight;
                    CurrentTestLog.Questions.Add(testLogQuestions);
                }
            }

            return IsRight;
        }

        private bool CheckQuestMulti()
        {
            var component = (uiAnswerSelect)panelAnswer.FindName("AnswerSelect");
            bool IsRight = false;

            var testLogQuestions = new TestLogQuestions();
            testLogQuestions.QuestionID = CurrentTest.Questions[CurrentQuestion].QuestionID;
            testLogQuestions.QuestionText = CurrentTest.Questions[CurrentQuestion].QuestionText;

            var count = 0;
            var trued = 0;
            foreach (AnswerInfo item in component.listAnswer.Items)
            {
                if (item.IsSelected)
                {
                    if (item.AnswerTrue) count++;

                    if (testLogQuestions.AnswerText == null)
                        testLogQuestions.AnswerText = item.AnswerID.ToString();
                    else
                        testLogQuestions.AnswerText += String.Format(";{0}", item.AnswerID);
                }

                if (item.AnswerTrue) trued ++;
            }

            if (count == trued) IsRight = true;
            testLogQuestions.IsRight = IsRight;
            CurrentTestLog.Questions.Add(testLogQuestions);

            return IsRight;
        }

        private bool CheckQuestArrange()
        {
            var component = (uiAnswerArrange)panelAnswer.FindName("AnswerArrange");
            bool IsRight = false;

            var count = 0;
            for (var i = 0; i < CurrentTest.Questions[CurrentQuestion].Answers.Count(); i++)
            {
                var n = CurrentTest.Questions[CurrentQuestion].Answers[i].AnswerNumber - 1;
                if (component.ItemsList[n].AnswerNumber == CurrentTest.Questions[CurrentQuestion].Answers[i].AnswerNumber) count++;
            }

            if (count == CurrentTest.Questions[CurrentQuestion].Answers.Count()) IsRight = true;
            var testLogQuestions = new TestLogQuestions();
            testLogQuestions.QuestionID = CurrentTest.Questions[CurrentQuestion].QuestionID;
            testLogQuestions.QuestionText = CurrentTest.Questions[CurrentQuestion].QuestionText;
            testLogQuestions.IsRight = IsRight;
            CurrentTestLog.Questions.Add(testLogQuestions);

            return IsRight;
        }

        //TODO: FIX: Исправить проверку вопроса "Соотнесение"
        private bool CheckQuestRelation()
        {
            var component = (uiAnswerRelation)panelAnswer.FindName("AnswerRelation");
            bool IsRight = false;
            ObservableCollection<AnswerInfo> Answers = ToObservableCollection(CurrentTest.Questions[CurrentQuestion].Answers.Where(e => e.RowNumber == 2));

            var count = 0;
            for (var i = 0; i < Answers.Count(); i++)
            {
                var n = Answers[i].AnswerNumber - 1;
                if (component.ItemsList[n].AnswerNumber == Answers[i].AnswerNumber) count++;
            }
            if (count == Answers.Count()) IsRight = true;

            return IsRight;
        }

        private bool CheckQuestSimpleText()
        {
            bool IsRight = false;
            var component = (uiAnswerText)panelAnswer.FindName("AnswerSimpleText");
            string AnswerText = component.textAnswer.Text;
            if (AnswerText == CurrentTest.Questions[CurrentQuestion].AnswerLite)
            {
                IsRight = true;
                var testLogQuestions = new TestLogQuestions();
                testLogQuestions.QuestionID = CurrentTest.Questions[CurrentQuestion].QuestionID;
                testLogQuestions.QuestionText = CurrentTest.Questions[CurrentQuestion].QuestionText;
                testLogQuestions.AnswerText = AnswerText;
                testLogQuestions.IsRight = IsRight;
                CurrentTestLog.Questions.Add(testLogQuestions);
            };

            return IsRight;
        }
        #endregion


        private void buttonAnswer_Click(object sender, RoutedEventArgs e)
        {
            if (CurrentTestLog.State == TestLog.TestingState.TS_FINISHED) return;

            CheckAnswer();
            if (CurrentQuestion < CurrentTest.QuestionCount - 1)
            {
                CurrentQuestion++;
                InitQuestion();
                //questionPassTime = new TimeSpan(0, 0, 0);
            }
            else
            {
                FinishTest();
            }
        }

        private void buttonAbort_Click(object sender, RoutedEventArgs e)
        {
            FinishTest();
            var mp = (MainPage)Application.Current.RootVisual;
            mp.mainFrame.GoBack();
        }

        public static ObservableCollection<T> ToObservableCollection<T>(IEnumerable<T> enumerableList)
        {
            if (enumerableList != null)
            {
                var observableCollection = new ObservableCollection<T>();
                foreach (var item in enumerableList)
                    observableCollection.Add(item);
                return observableCollection;
            }
            return null;
        }
    }

    //TODO: ADD: Тип вопросов (нужно ли это?)
    public enum QuestionType
    {
        QT_Text = 1,
        QT_FormattedText = 2,
        QT_Audio = 3,
        QT_Video = 4
    }

    //Тип ответов
    public enum AnswerType
    {
        AT_Binary = 1,
        AT_SelectOne = 2,
        AT_SelectMulti = 3,
        AT_Arrange = 4,
        AT_Relation = 5,
        AT_SimpleText = 6
    }

    public class TestInfo
    {
        public int TestID { get; set; }
        public int SubjectID { get; set; }
        public string SubjectName { get; set; }
        public string SubjectAbbr { get; set; }
        public string TestName { get; set; }
        public int QuestionCount { get; set; }
        public int TimeTotal { get; set; }

        public bool ShuffleQuestions { get; set; }
        public bool ShuffleAnswers { get; set; }
        public bool ShowTestRules { get; set; }  //TODO: ADD: Показать правила тестирования
        public int TestMode { get; set; }        //TODO: NEW: Выбрать режим тестирования
        public int TestRating { get; set; }      //TODO: Срочно: Выставление рейтинга (разобраться)
        public bool AllowRefuse { get; set; }    //TODO: ADD: Разрешить отказ от ответа
        public bool AllowTips { get; set; }      //TODO: NEW: Использование подсказок
        public int QuestionResult { get; set; }
        public bool ResultShow { get; set; }     //TODO: Срочно: Настройка вывода результата
        public bool ResultSave { get; set; }
        public bool ResultPrint { get; set; }

        public ObservableCollection<QuestionInfo> Questions { get; set; }

        public TestInfo()
        {
            Questions = new ObservableCollection<QuestionInfo>();
        }
    }

    public class QuestionInfo
    {
        public int QuestionID { get; set; }
        public string QuestionText { get; set; }
        public QuestionType QuestionType { get; set; }
        public AnswerType AnswerType { get; set; }
        public int QuestionDifficulty { get; set; }     
        public bool AnswerImage { get; set; }
        public string AnswerLite { get; set; } //экспериментальное свойство

        public ObservableCollection<AnswerInfo> Answers { get; set; }

        public QuestionInfo()
        {
            Answers = new ObservableCollection<AnswerInfo>();
        }
    }

    public class AnswerInfo
    {
        public int AnswerID { get; set; }
        public string AnswerText { get; set; }
        public bool AnswerTrue { get; set; }
        public int AnswerNumber { get; set; }
        public int RowNumber { get; set; }

        public string Image { get; set; }
        public bool IsSelected { get; set; }
    }

    public class TestLog
    {
        public int UserID { get; set; }
        public int TestID { get; set; }
        public int RightAnswers { get; set; }
        public int TestRating { get; set; }
        public DateTime DateStart { get; set; }
        public DateTime DateFinish { get; set; }
        public string UserFullName { get; set; }
        public string GroupName { get; set; }
        public string SubjectName { get; set; }
        public string TestName { get; set; }
        public int TotalTime { get; set; }
        public int QuestionCount { get; set; }

        public TestingState State { get; set; }
        public enum TestingState
        {
            TS_WAIT = 1,
            TS_PROGRESS = 2,
            TS_FINISHED = 3,
        }

        public ObservableCollection<TestLogQuestions> Questions { get; set; }

        public TestLog()
        {
            State = TestingState.TS_WAIT;
            Questions = new ObservableCollection<TestLogQuestions>();
        }
    }

    public class TestLogQuestions
    {
        public int ResultID { get; set; }
        public int QuestionID { get; set; }

        public string QuestionText { get; set; }
        public string AnswerText { get; set; }

        public bool IsRight { get; set; }
    }
}